home *** CD-ROM | disk | FTP | other *** search
/ Programming a Multiplayer FPS in DirectX / Programming a Multiplayer FPS in DirectX (Companion CD).iso / DirectX / dxsdk_oct2004.exe / dxsdk.exe / Samples / Managed / Direct3D / Scripting / Scripting.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2004-09-27  |  12.6 KB  |  366 lines

  1. //--------------------------------------------------------------------------------------
  2. // File: Scripting.cpp
  3. //
  4. // Scripting code for Managed Scripting sample
  5. //
  6. // Copyright (c) Microsoft Corporation. All rights reserved.
  7. //--------------------------------------------------------------------------------------
  8. #include "dxstdafx.h"
  9.  
  10. #pragma managed
  11.  
  12. // Undef this
  13. #ifdef GetTempFileName
  14. #undef GetTempFileName
  15. #endif
  16.  
  17. // User defined types
  18. #define SCRIPT_TYPE_NAME S"ScriptClass"
  19. #define SCRIPT_UPDATE_POSITION S"UpdatePosition"
  20. #define SCRIPT_UPDATE_ANGLEX S"UpdateRotationX"
  21. #define SCRIPT_UPDATE_ANGLEY S"UpdateRotationY"
  22. #define SCRIPT_UPDATE_ANGLEZ S"UpdateRotationZ"
  23.  
  24. // We will need to have the CLR loaded
  25. #using <mscorlib.dll>
  26. #using <system.dll>
  27.  
  28. // These are the namespaces required
  29. using namespace System;
  30. using namespace System::IO;
  31. using namespace System::Reflection;
  32. using namespace System::CodeDom;
  33. using namespace System::CodeDom::Compiler;
  34. // Security namespaces
  35. using namespace System::Security;
  36. using namespace System::Security::Policy;
  37. using namespace System::Security::Permissions;
  38. // For code compiler
  39. using namespace Microsoft::CSharp;
  40.  
  41. __sealed public __gc class ScriptEngine
  42. {
  43. private:
  44.     static Assembly* pScriptAssembly = NULL; // The assembly that hold the scripts
  45.     static Type* pScriptType = NULL; // The class that holds the scripts
  46.     static String* pSavedFile = NULL; // The assembly saved location
  47.  
  48.     static bool canUpdatePosition = true;
  49.     static bool canUpdateRotationX = true;
  50.     static bool canUpdateRotationY = true;
  51.     static bool canUpdateRotationZ = true;
  52.     static bool hasNotifiedSecurityException = false;
  53.  
  54.     // Reset script options
  55.     static void ResetObjects()
  56.     {
  57.         pScriptAssembly = NULL;
  58.         pScriptType = NULL;
  59.         canUpdatePosition = true;
  60.         canUpdateRotationX = true;
  61.         canUpdateRotationY = true;
  62.         canUpdateRotationZ = true;
  63.         hasNotifiedSecurityException = false;
  64.  
  65.         // Delete the saved file if possible
  66.         if ( (pSavedFile != NULL) && (pSavedFile->Length > 0) )
  67.         {
  68.             try
  69.             {
  70.                 File::Delete(pSavedFile);
  71.             }
  72.             catch(Exception*)
  73.             {
  74.                 // Ignore
  75.             }
  76.             pSavedFile = NULL;
  77.         }
  78.     }
  79.  
  80. public:
  81.     // Initialize the scripting engine's app domain
  82.     static HRESULT Initialize()
  83.     {
  84.         try
  85.         {
  86.             // Create the security policy level for this application domain
  87.             PolicyLevel* pSecurityLevel = PolicyLevel::CreateAppDomainLevel();
  88.  
  89.             // Create a new, empty permission set so we don't mistakenly grant some permission we don't want
  90.             PermissionSet* pPermissions = new PermissionSet(PermissionState::None);
  91.  
  92.             // Set the permissions that you will allow, in this case we only want to allow execution of code
  93.             pPermissions->AddPermission(new SecurityPermission(SecurityPermissionFlag::Execution));
  94.                                                                            
  95.             // Make sure we have the permissions currently
  96.             pPermissions->Demand();
  97.  
  98.             // Give the policy level's root code group a new policy statement based
  99.             // on the new permission set.
  100.             pSecurityLevel->RootCodeGroup->PolicyStatement = new PolicyStatement(pPermissions);
  101.  
  102.             // Update the application domain's policy now
  103.             AppDomain::CurrentDomain->SetAppDomainPolicy(pSecurityLevel);
  104.         }
  105.         catch(Exception*)
  106.         {
  107.             return E_FAIL;
  108.         }
  109.  
  110.         return S_OK;
  111.     }
  112.  
  113.     static HRESULT LoadScriptData(System::String* pScriptName)
  114.     {
  115.         // Make sure to reset the objects first
  116.         ResetObjects();
  117.  
  118.         // Make sure a valid name was passed in
  119.         if (pScriptName == NULL || pScriptName->Length == 0)
  120.             return E_INVALIDARG;
  121.         // First try to open the script file
  122.         StreamReader* pReader = NULL;
  123.         try
  124.         {
  125.             pReader = new StreamReader(pScriptName);
  126.  
  127.             // Now try to read the text
  128.             System::String* pScriptText = pReader->ReadToEnd();
  129.             
  130.             // Make sure something was read
  131.             if (pScriptText == NULL || pScriptText->Length == 0)
  132.                 return E_INVALIDARG;
  133.  
  134.             // First create the compilers
  135.             CSharpCodeProvider* pProvider = new CSharpCodeProvider();
  136.             ICodeCompiler* pCompiler = pProvider->CreateCompiler();
  137.             CompilerParameters* pParams = new CompilerParameters();
  138.  
  139.             // Now try to compile this script, first make sure we compile an assembly, not exe
  140.             pParams->GenerateExecutable = false;
  141.  
  142.             // Make sure the assembly is generated in the temp files, first get a temp file name
  143.             pSavedFile = System::String::Concat(Path::GetTempFileName(), S".dll");
  144.             // Next mark it as not being generated in memory
  145.             pParams->GenerateInMemory = false;
  146.             // Finally, update the output file
  147.             pParams->OutputAssembly = pSavedFile;
  148.             #if defined(DEBUG) | defined(_DEBUG)
  149.             // If you want to include debug information, do so
  150.             pParams->IncludeDebugInformation = true;
  151.             #endif
  152.  
  153.             // Finally compile the code
  154.             CompilerResults* pResult = pCompiler->CompileAssemblyFromSource(pParams, pScriptText);
  155.             
  156.             if (pResult->Errors->Count > 0)
  157.             {
  158.                 // Some errors occurred
  159.                 return E_FAIL;
  160.             }
  161.             else
  162.             {
  163.                 // The compilation was a success, load the assembly 
  164.                 pScriptAssembly = System::Reflection::Assembly::LoadFrom(pResult->PathToAssembly);
  165.                 // Try to load the type
  166.                 pScriptType = pScriptAssembly->GetType(SCRIPT_TYPE_NAME, false, true);
  167.                 if (pScriptType == NULL)
  168.                 {
  169.                     // Couldn't find the type, fail
  170.                     pScriptAssembly = NULL;
  171.                     pScriptType = NULL;
  172.                     return E_FAIL;
  173.                 }
  174.                 
  175.                 // Finished
  176.                 return S_OK;
  177.             }
  178.         }
  179.         catch (Exception* e)
  180.         {
  181.             System::Diagnostics::Debugger::Log(0, NULL, e->ToString());
  182.             // Reset objects
  183.             ResetObjects();
  184.             // Reading the script file failed, return failure
  185.             return E_FAIL;
  186.         }
  187.         __finally
  188.         {
  189.             // Make sure to close the file down no matter what
  190.             if (pReader != NULL)
  191.             {
  192.                 IDisposable* pDisposeObject = dynamic_cast<IDisposable*>(pReader);
  193.                 if (pDisposeObject != NULL)
  194.                     pDisposeObject->Dispose();
  195.             }
  196.         }
  197.  
  198.     }
  199.     static HRESULT UpdatePlayerPosition(double appTime, float __nogc* pX, float __nogc* pY, float __nogc* pZ)
  200.     {
  201.         // Check params
  202.         if (pX == NULL || pY == NULL || pZ == NULL)
  203.             return E_INVALIDARG;
  204.  
  205.         // Check options
  206.         if (pScriptAssembly == NULL || pScriptType == NULL)
  207.             return E_FAIL;
  208.  
  209.         // Can the position be updated?
  210.         if (!canUpdatePosition)
  211.             return E_FAIL;
  212.  
  213.         // Now try to call the method
  214.         try
  215.         {
  216.             // Create the parameters
  217.             System::Object* pParams __gc[] = { __box(appTime), __box(*pX), __box(*pY), __box(*pZ) };
  218.             pScriptType->InvokeMember(SCRIPT_UPDATE_POSITION, (BindingFlags)(BindingFlags::InvokeMethod | BindingFlags::DeclaredOnly |
  219.                 BindingFlags::Public | BindingFlags::NonPublic | BindingFlags::Static), NULL, NULL, pParams);
  220.  
  221.             // The method succeeded, update the data
  222.             *pX = *static_cast<__box float*>(pParams[1]);
  223.             *pY = *static_cast<__box float*>(pParams[2]);
  224.             *pZ = *static_cast<__box float*>(pParams[3]);
  225.         }
  226.         catch(TargetInvocationException* e)
  227.         {
  228.             if ( (dynamic_cast<SecurityException*>(e->InnerException) != NULL) 
  229.                 || (dynamic_cast<PolicyException*>(e->InnerException) != NULL) )
  230.             {
  231.                 // Special case the security exceptions
  232.                 if (!hasNotifiedSecurityException)
  233.                 {
  234.                     MessageBox(NULL, L"This script has attempted to do something the security system will not allow.  Please verify this script is safe to run.", 
  235.                         L"Security Exception", MB_OK);
  236.                     hasNotifiedSecurityException = true;
  237.                 }
  238.             }
  239.             canUpdatePosition = false;
  240.             // Invoke failed
  241.             return E_FAIL;
  242.         }
  243.  
  244.         return S_OK;
  245.     }
  246.     static HRESULT UpdatePlayerRotation(System::String* pMethodName, double appTime, float __nogc* pAngle)
  247.     {
  248.         // Check params
  249.         if (pAngle == NULL)
  250.             return E_INVALIDARG;
  251.  
  252.         // Make sure a valid name was passed in
  253.         if (pMethodName == NULL || pMethodName->Length == 0)
  254.             return E_INVALIDARG;
  255.  
  256.         // Check options
  257.         if (pScriptAssembly == NULL || pScriptType == NULL)
  258.             return E_FAIL;
  259.  
  260.         // Can we call?
  261.         if (pMethodName->Equals(SCRIPT_UPDATE_ANGLEX))
  262.             if (!canUpdateRotationX)
  263.                 return E_FAIL;
  264.         if (pMethodName->Equals(SCRIPT_UPDATE_ANGLEY))
  265.             if (!canUpdateRotationY)
  266.                 return E_FAIL;
  267.         if (pMethodName->Equals(SCRIPT_UPDATE_ANGLEZ))
  268.             if (!canUpdateRotationZ)
  269.                 return E_FAIL;
  270.  
  271.         // Now try to call the method
  272.         try
  273.         {
  274.             // Create the parameters
  275.             System::Object* pParams __gc[] = { __box(appTime), __box(*pAngle) };
  276.             pScriptType->InvokeMember(pMethodName, (BindingFlags)(BindingFlags::InvokeMethod | BindingFlags::DeclaredOnly |
  277.                 BindingFlags::Public | BindingFlags::NonPublic | BindingFlags::Static), NULL, NULL, pParams);
  278.  
  279.             // The method succeeded, update the data
  280.             *pAngle = *static_cast<__box float*>(pParams[1]);
  281.         }
  282.         catch(Exception*)
  283.         {
  284.             if (pMethodName->Equals(SCRIPT_UPDATE_ANGLEX))
  285.                 canUpdateRotationX = false;
  286.             if (pMethodName->Equals(SCRIPT_UPDATE_ANGLEY))
  287.                 canUpdateRotationY = false;
  288.             if (pMethodName->Equals(SCRIPT_UPDATE_ANGLEZ))
  289.                 canUpdateRotationZ = false;
  290.             // Invoke failed
  291.             return E_FAIL;
  292.         }
  293.  
  294.         return S_OK;
  295.     }
  296. };
  297.  
  298. // Initializes the scripting engine
  299. HRESULT InitializeScriptEngine()
  300. {
  301.     return ScriptEngine::Initialize();
  302. }
  303.  
  304. // Call in to load a script
  305. HRESULT LoadScript(LPWSTR pScriptFileName)
  306. {
  307.     return ScriptEngine::LoadScriptData(pScriptFileName);
  308. }
  309.  
  310. // Call in to the update player position script
  311. HRESULT UpdatePlayerPosition(double appTime, float __nogc* pX, float __nogc* pY, float __nogc* pZ)
  312. {
  313.     return ScriptEngine::UpdatePlayerPosition(appTime, pX, pY, pZ);
  314. }
  315.  
  316. // Call in to the update player rotation script
  317. HRESULT UpdatePlayerRotationX(double appTime, D3DXMATRIX __nogc* pMatrix)
  318. {
  319.     // Calculate the new rotation angle
  320.     float angle;
  321.     if ( SUCCEEDED(ScriptEngine::UpdatePlayerRotation(SCRIPT_UPDATE_ANGLEX, appTime, &angle)) )
  322.     {
  323.         D3DXMATRIX mRotation;
  324.         // Rotate the X
  325.         D3DXMatrixRotationX(&mRotation, angle);
  326.         D3DXMatrixMultiply(pMatrix, pMatrix, &mRotation );
  327.     }
  328.     else
  329.         return E_FAIL;
  330.  
  331.     return S_OK;
  332. }
  333.  
  334. HRESULT UpdatePlayerRotationY(double appTime, D3DXMATRIX __nogc* pMatrix)
  335. {
  336.     // Calculate the new rotation angle
  337.     float angle;
  338.     if ( SUCCEEDED(ScriptEngine::UpdatePlayerRotation(SCRIPT_UPDATE_ANGLEY, appTime, &angle)) )
  339.     {
  340.         D3DXMATRIX mRotation;
  341.         // Rotate the Y
  342.         D3DXMatrixRotationY(&mRotation, angle);
  343.         D3DXMatrixMultiply(pMatrix, pMatrix, &mRotation );
  344.     }
  345.     else
  346.         return E_FAIL;
  347.  
  348.     return S_OK;
  349. }
  350.  
  351. HRESULT UpdatePlayerRotationZ(double appTime, D3DXMATRIX __nogc* pMatrix)
  352. {
  353.     // Calculate the new rotation angle
  354.     float angle;
  355.     if ( SUCCEEDED(ScriptEngine::UpdatePlayerRotation(SCRIPT_UPDATE_ANGLEZ, appTime, &angle)) )
  356.     {
  357.         D3DXMATRIX mRotation;
  358.         // Rotate the Z
  359.         D3DXMatrixRotationZ(&mRotation, angle);
  360.         D3DXMatrixMultiply(pMatrix, pMatrix, &mRotation );
  361.     }
  362.     else
  363.         return E_FAIL;
  364.  
  365.     return S_OK;
  366. }